# player.py
import pygame
from settings import *

# 使用向量进行精确的数学计算
vec = pygame.math.Vector2

class Player(pygame.sprite.Sprite):
    def __init__(self, game, x, y):
        super().__init__()
        self.game = game
        self.image = pygame.Surface((PLAYER_SIZE, PLAYER_SIZE))
        self.image.fill(PLAYER_COLOR)
        self.rect = self.image.get_rect()
        self.pos = vec(x, y)  # 位置向量
        self.vel = vec(0, 0)  # 速度向量
        self.rect.center = self.pos
        self.speed = PLAYER_SLOW_SPEED
        self.max_health = PLAYER_HEALTH
        self.health = self.max_health
        # 按键状态跟踪
        self.keys_pressed = {
            'up': False,
            'down': False,
            'left': False,
            'right': False
        }
        # 视野相关属性
        self.vision_radius = PLAYER_VISION_RADIUS
        self.vision_angle = PLAYER_VISION_ANGLE
        self.visible_area = []  # 可见区域的多边形点列表
        self.show_full_vision = False  # 是否显示完整视野（F键按下时）

    def update(self):
        # 检查玩家是否死亡
        if self.health <= 0:
            self.die()
            return
            
        # 右键移动逻辑将在game.py中处理，这里保持简单
        # 不再重置速度向量，因为速度可能由鼠标点击设置
        
        # 标准化对角线移动速度
        if self.vel.length() > 0:
            self.vel = self.vel.normalize() * self.speed

        # 根据速度更新位置
        self.pos += self.vel * self.game.dt
        self.rect.centerx = self.pos.x

        # 水平方向碰撞检测
        self.collide_with_obstacles('x')

        self.rect.centery = self.pos.y
        # 垂直方向碰撞检测
        self.collide_with_obstacles('y')

        # 防止玩家移出屏幕
        if self.rect.left < 0:
            self.rect.left = 0
            self.pos.x = self.rect.centerx
        if self.rect.right > WIDTH:
            self.rect.right = WIDTH
            self.pos.x = self.rect.centerx
        if self.rect.top < 0:
            self.rect.top = 0
            self.pos.y = self.rect.centery
        if self.rect.bottom > HEIGHT:
            self.rect.bottom = HEIGHT
            self.pos.y = self.rect.centery

    def draw_health_bar(self, surface):
        """绘制血条"""
        if self.health < self.max_health:
            # 血条尺寸
            bar_length = PLAYER_SIZE
            bar_height = 5
            # 血条位置（在玩家上方）
            bar_x = self.rect.x
            bar_y = self.rect.y - 10
            
            # 血条背景（红色）
            pygame.draw.rect(surface, (255, 0, 0), (bar_x, bar_y, bar_length, bar_height))
            
            # 当前血量（绿色）
            health_ratio = self.health / self.max_health
            pygame.draw.rect(surface, (0, 255, 0), (bar_x, bar_y, bar_length * health_ratio, bar_height))
    
    def collide_with_obstacles(self, dir):
        """与障碍物碰撞检测"""
        hits = pygame.sprite.spritecollide(self, self.game.obstacles, False)
        if hits:
            if dir == 'x':
                if self.vel.x > 0: # 向右移动
                    self.rect.right = hits[0].rect.left
                if self.vel.x < 0: # 向左移动
                    self.rect.left = hits[0].rect.right
                self.pos.x = self.rect.centerx
                self.vel.x = 0
            if dir == 'y':
                if self.vel.y > 0: # 向下移动
                    self.rect.bottom = hits[0].rect.top
                if self.vel.y < 0: # 向上移动
                    self.rect.top = hits[0].rect.bottom
                self.pos.y = self.rect.centery
                self.vel.y = 0
    
    def handle_key_down(self, key):
        """处理按键按下事件"""
        # 处理F键按下（显示完整视野）
        if key == pygame.K_f:
            self.show_full_vision = True
        # 不再处理WASD或方向键移动
        pass
    
    def handle_key_up(self, key):
        """处理按键释放事件"""
        # 处理F键释放
        if key == pygame.K_f:
            self.show_full_vision = False
        # 不再处理WASD或方向键移动
        pass
    
    def reset_keys(self):
        """重置所有按键状态"""
        for key in self.keys_pressed:
            self.keys_pressed[key] = False
    
    def calculate_vision_area(self):
        """计算玩家的视野区域（考虑障碍物遮挡）"""
        import math
        from settings import FOG_OF_WAR
        
        # 如果不在迷雾模式下，返回空列表（表示全屏可见）
        if not FOG_OF_WAR:
            self.visible_area = []
            return []
        
        # 获取玩家位置
        center_x, center_y = self.pos.x, self.pos.y
        
        # 获取鼠标位置作为视野方向
        mouse_x, mouse_y = pygame.mouse.get_pos()
        
        # 计算从玩家到鼠标的角度
        angle_to_mouse = math.atan2(mouse_y - center_y, mouse_x - center_x)
        
        # 视野参数
        vision_radius = self.vision_radius
        vision_angle = self.vision_angle * (math.pi / 180)  # 转换为弧度
        
        # 生成扇形视野区域
        num_points = 30  # 扇形边缘的点数
        self.visible_area = [(center_x, center_y)]  # 从玩家位置开始
        
        # 生成扇形边缘点
        start_angle = angle_to_mouse - vision_angle / 2
        for i in range(num_points):
            angle = start_angle + (vision_angle * i / (num_points - 1))
            # 计算射线终点
            end_x = center_x + vision_radius * math.cos(angle)
            end_y = center_y + vision_radius * math.sin(angle)
            
            # 检查射线与障碍物的交点
            closest_point = self.raycast(center_x, center_y, end_x, end_y)
            self.visible_area.append(closest_point)
        
        # 总是返回完整的可见区域，让apply_fog_of_war决定是否显示边界
        return self.visible_area
    
    def raycast(self, start_x, start_y, end_x, end_y):
        """从起点到终点发射射线，返回最近的交点或终点"""
        import math
        
        # 获取所有障碍物
        obstacles = self.game.obstacles.sprites()
        
        # 初始化最近交点为射线终点
        closest_point = (end_x, end_y)
        min_distance = math.sqrt((end_x - start_x)**2 + (end_y - start_y)**2)
        
        # 检查射线与每个障碍物的交点
        for obstacle in obstacles:
            # 获取障碍物的边界框
            rect = obstacle.rect
            
            # 计算射线与矩形边界的交点
            intersection_points = self.get_ray_rect_intersection(
                start_x, start_y, end_x, end_y,
                rect.left, rect.top, rect.width, rect.height
            )
            
            # 如果有交点，找到最近的交点
            for point in intersection_points:
                distance = math.sqrt((point[0] - start_x)**2 + (point[1] - start_y)**2)
                if distance < min_distance:
                    min_distance = distance
                    closest_point = point
        
        return closest_point
    
    def get_ray_rect_intersection(self, ray_start_x, ray_start_y, ray_end_x, ray_end_y, 
                                 rect_x, rect_y, rect_width, rect_height):
        """计算射线与矩形的交点"""
        # 矩形的四条边
        edges = [
            (rect_x, rect_y, rect_x + rect_width, rect_y),  # 上边
            (rect_x + rect_width, rect_y, rect_x + rect_width, rect_y + rect_height),  # 右边
            (rect_x + rect_width, rect_y + rect_height, rect_x, rect_y + rect_height),  # 下边
            (rect_x, rect_y + rect_height, rect_x, rect_y)  # 左边
        ]
        
        intersection_points = []
        
        # 检查射线与每条边的交点
        for edge_start_x, edge_start_y, edge_end_x, edge_end_y in edges:
            intersection = self.get_line_intersection(
                ray_start_x, ray_start_y, ray_end_x, ray_end_y,
                edge_start_x, edge_start_y, edge_end_x, edge_end_y
            )
            
            if intersection:
                # 检查交点是否在矩形边上（包括端点）
                if (min(edge_start_x, edge_end_x) - 0.1 <= intersection[0] <= max(edge_start_x, edge_end_x) + 0.1 and
                    min(edge_start_y, edge_end_y) - 0.1 <= intersection[1] <= max(edge_start_y, edge_end_y) + 0.1):
                    intersection_points.append(intersection)
        
        return intersection_points
    
    def get_line_intersection(self, x1, y1, x2, y2, x3, y3, x4, y4):
        """计算两条线段的交点"""
        # 计算分母
        denominator = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4)
        
        # 如果分母为0，表示两条线平行或共线，没有交点
        if abs(denominator) < 1e-10:
            return None
        
        # 计算交点
        t = ((x1 - x3) * (y3 - y4) - (y1 - y3) * (x3 - x4)) / denominator
        u = -((x1 - x2) * (y1 - y3) - (y1 - y2) * (x1 - x3)) / denominator
        
        # 检查交点是否在两条线段上
        if 0 <= t <= 1 and 0 <= u <= 1:
            intersection_x = x1 + t * (x2 - x1)
            intersection_y = y1 + t * (y2 - y1)
            return (intersection_x, intersection_y)
        
        return None

    def is_position_visible(self, x, y):
        """检查指定位置是否在玩家视野内（考虑障碍物遮挡）"""
        from settings import FOG_OF_WAR
        
        # 如果不在迷雾模式下，所有位置都可见
        if not FOG_OF_WAR:
            return True
        
        # 如果F键被按下，显示完整视野，使用相同的可见性判断逻辑
        # 如果视野区域未计算，先计算
        if not self.visible_area:
            self.calculate_vision_area()
        
        # 检查点是否在扇形区域内
        point_x, point_y = x, y
        
        # 首先检查距离
        distance = pygame.math.Vector2(point_x - self.pos.x, point_y - self.pos.y).length()
        if distance > self.vision_radius:
            return False
        
        # 检查角度
        dx = point_x - self.pos.x
        dy = point_y - self.pos.y
        point_angle = pygame.math.Vector2(dx, dy).angle_to(pygame.math.Vector2(1, 0))
        
        # 获取鼠标位置计算玩家朝向
        mouse_x, mouse_y = pygame.mouse.get_pos()
        player_dx = mouse_x - self.pos.x
        player_dy = mouse_y - self.pos.y
        player_angle = pygame.math.Vector2(player_dx, player_dy).angle_to(pygame.math.Vector2(1, 0))
        
        # 检查角度是否在视野范围内
        angle_diff = abs(point_angle - player_angle)
        if angle_diff > 180:
            angle_diff = 360 - angle_diff
        
        if angle_diff > self.vision_angle / 2:
            return False
        
        # 如果通过了基本检查，再检查是否被障碍物遮挡
        # 从玩家位置到目标位置发射射线
        closest_point = self.raycast(self.pos.x, self.pos.y, point_x, point_y)
        
        # 计算交点到玩家的距离
        occlusion_distance = pygame.math.Vector2(closest_point[0] - self.pos.x, 
                                               closest_point[1] - self.pos.y).length()
        
        # 如果交点距离小于目标点距离，说明被障碍物遮挡
        return occlusion_distance >= distance - 1  # 减1是为了避免浮点误差

    def die(self):
        """玩家死亡处理"""
        print("玩家死亡！游戏结束！")
        self.kill()
        # 触发游戏结束事件
        self.game.game_over = True
    
    def shoot(self, target_pos):
        """玩家射击方法"""
        # 计算射击方向
        direction = vec(target_pos) - self.pos
        if direction.length() > 0:
            direction = direction.normalize()
        
        # 创建子弹
        from sprites.bullet import Bullet
        bullet = Bullet(self.game, self.pos, direction)
        self.game.bullets.add(bullet)
        self.game.all_sprites.add(bullet)  # 添加到all_sprites组中，确保子弹被更新